#pragma once

#include "Types.h"

#include <MyFC/CustomWindow.h>
#include <MyFC/Glyph.h>
#include <vector>

namespace My {

class RowControl;
class ListControl;

typedef std::vector<RowControl *> RowVector;

class ListControl : public CustomWindow<CWnd> {
	friend class RowControl;
public:
	typedef CustomWindow<CWnd> Base;
private:
	int			m_Range;
	int			m_Page;
	int			m_Offset;
	RowVector	m_Rows;
	My::Size 	m_Invalid;
	My::Size 	m_First;
	My::Size 	m_Last;
	int			m_ActiveRow;
private:
	void SetOffset(int offset);
	void UpdateOffset()
		{ SetOffset(m_Offset); }
	void UpdatePage();
	void UpdateScrollBar();
protected:
	void InvalidateRows(My::Size from);
	void UpdateRows();
	virtual void OnRowsChanged() { }
private:
	static const AFX_MSGMAP_ENTRY _messageEntries[];
protected:
	static const AFX_MSGMAP messageMap;
	static const AFX_MSGMAP* PASCAL GetThisMessageMap();
	virtual DLL_API const AFX_MSGMAP * GetMessageMap() const;
protected:
	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar ); 
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnDestroy();
	afx_msg BOOL OnEraseBkgnd(CDC *);
public:
	DLL_API ListControl();
	DLL_API ~ListControl();
public:
	DLL_API int GetRange() const
		{ return m_Range; }
	DLL_API int GetPage() const
		{ return m_Page; }
	DLL_API int GetOffset() const
		{ return m_Offset; }
	DLL_API My::Size GetRowCount() const
		{ return m_Rows.size(); }
	DLL_API RowControl * GetRow(My::Size index) const
		{ return m_Rows[index]; }
	DLL_API bool IsEmpty() const
		{ return m_Rows.empty(); }
	DLL_API int GetActiveRow() const
		{ return m_ActiveRow; }
	DLL_API RowControl * GetActiveRowPtr() const { 
		ASSERT(m_ActiveRow != -1); 
		return GetRow(m_ActiveRow); 
	}
	DLL_API void SetActiveRow(int);
	DLL_API void SetValidActiveRow(int);
public:
	virtual DLL_API void UpdateBounds();
	virtual DLL_API void Paint(CDC * pDC, const CRect & r);
	virtual DLL_API void HandleKeyDown(unsigned int key, unsigned int count, unsigned int flags);
	virtual DLL_API void HandleLeftDown(unsigned int flags, const CPoint & p);
	virtual DLL_API void HandleFocus();
	virtual DLL_API void HandleUnfocus();
public:
	DLL_API int RowIndexAt(int y);
	DLL_API void ClampInView(My::Size);
	DLL_API void InsertRows(My::Size pos, RowControl * * pRows, My::Size count);
	DLL_API void RemoveRows(My::Size pos, My::Size count);
	DLL_API void Clear();
};

class DLL_API RowControl : public virtual Control {
	friend class ListControl;
private:
	ListControl &	m_Owner;
	int				m_RowIndex;
	int				m_RowOffset;
	int				m_RowHeight;
public:
	RowControl(ListControl & owner);
	~RowControl();
protected:
	ListControl & GetOwner() const
		{ return m_Owner; }
	void SetRowHeight(int h);
public:
	virtual CRect Bounds() const;
public:
	int GetRowIndex() const
		{ return m_RowIndex; }
	int GetRowOffset() const
		{ return m_RowOffset; }
	int GetRowHeight() const
		{ return m_RowHeight; }
};

class DLL_API StdRowControl : public RowControl {
public:
	StdRowControl(ListControl &);
public:
	virtual void HandlePaint(CDC * pDC, const CRect & r);
	virtual void HandleLeftDoubleClick(unsigned int flags, const CPoint & p);
	virtual void HandleLeftDown(unsigned int flags, const CPoint & p);
protected:
	virtual String GetCaption() const = 0;
	virtual bool IsExpandable() const { return false; }
	virtual bool IsExpanded() const { return false; }
	virtual void Expand() { }
	virtual void Collapse() { } 
	virtual My::Size GetLevel() { return 0; }
protected:
	My::Size	m_Indent;
	Glyph		m_ButtonUp;
	Glyph		m_ButtonDown;
	CRect		m_ButtonRect;
};

} // My